# coding=utf-8
import json

import jsonpath
import simplejson
from jsonpath_ng.ext import parse
from api.common_api import Common_Api
from common.db import *
from common.utils import Utils
utils = Utils()

class Workflow_Outside(Common_Api):

    def get_wf_token(self,user_guid=''):
        """
        通过usercode，获取AuthenticationHeader
        :param body: {"secret": "4230BC6E-69E6-46A9-A39E-B929A06A84E8"}，secret值则是用户id
        :return:
        """
        url = '/wf/api/Common/Token'
        resp = self.send(url, body=user_guid, method='post', headers={"Content-Type": "application/json"})
        return resp

    def IsCanCancelProcess(self,body,user_guid='',AuthenticationHeader=''):
        """
        判断是否能够业务系统作废接口,body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/ProcessEntiy/IsCanCancelProcess'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url,method='post',body=body,headers={"AuthenticationHeader":AuthenticationHeader,"Content-Type": "application/json"})
        return resp

    def CancelProcess(self,body,user_guid='',AuthenticationHeader=''):
        """
        业务系统作废流程接口（标准产品），body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/ProcessEntiy/CancelProcess'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def GetProcessStatus(self,body,user_guid='',AuthenticationHeader=''):
        """
        批量获取流程状态信息(标准产品接口，成本)，body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/ProcessEntiy/GetProcessStatus'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def GetCurAuditor(self,body,user_guid='',AuthenticationHeader=''):
        """
        根据业务获取当前步骤和责任人信息接口(雅居乐重构成本)，body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/ProcessEntiy/GetCurAuditor'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def GetProcessEntityByBusiness(self,body,user_guid='',AuthenticationHeader=''):
        """
        通过业务GUID和业务类型获取流程实例接口，body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/ProcessEntiy/GetProcessEntityByBusiness'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def GetApproveStepsView(self,body,user_guid='',AuthenticationHeader=''):
        """
        获得审批记录接口，body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/ProcessEntiy/GetApproveStepsView'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp


    def IsCanDeleteBusiness(self,body,user_guid='',AuthenticationHeader=''):
        """
        判断是否能够删除业务数据，body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/ProcessEntiy/IsCanDeleteBusiness'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', body=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def _build_AutoInitiate_body(self,user,ProcessModuleName='',BusinessGUID='',body=''):
        """
        构建静默发起相关请求的基础参数。
        :param user: 用户code。
        :param ProcessName: 模板名称。
        :param BusinessGUID: 业务GUID。
        :param body: 请求体，当使用模板名称和业务GUID进行发起时，不需要body参数。反之，则需要完整body参数。
        :return: 返回user_guid和body两个元素组成的字典。
        """
        # 通过请求获取用户组织信息
        user_orgs = self.get_users_by_name(user)
        user_default = self.jsonpath_value(user_orgs.json(), '$.data.data[0].org_settings[?(@.is_default=="1" or @.is_default==1)]')
        org_id = user_default['org_id']
        name_path = user_default['name_path']
        Logger.info(f'用户【{user}】默认组织：【{name_path}】，对应组织GUID：【{org_id}】')
        # 用户基本信息
        user_base_info = self.jsonpath_value(user_orgs.json(), '$.data.data[0]')
        user_name = user_base_info['name']
        user_guid = user_base_info['id']
        if body == "":
            # 查询流程模板相关信息
            sql = f"""SELECT m.ProcessName '流程模板',m.ProcessGUID '流程模板GUID',t.name '业务类型' FROM dbo.WfProcess m 
                                INNER JOIN dbo.wfd_package p ON m.PackageId=p.id
                                INNER JOIN dbo.wfd_package_type t ON p.type_id= t.id
                                WHERE ProcessName='{ProcessModuleName}' and m.Status=2
                                """
            result = sqlserver_query_return_contain_field(sql)  # 执行sql
            # 获取sql返回的数据，对应的字段信息
            ProcessModuleGUID = utils.get_column_value_by_two_array(result, '流程模板GUID')[0]
            BusinessType = utils.get_column_value_by_two_array(result, '业务类型')[0]
            body = {
                "BusinessGUID": BusinessGUID,
                "BusinessType": BusinessType,
                "InitiateUserGUID": user_guid,
                "InitiateUserName": user_name,
                "InitiateDepartGUID": org_id,
                "CurrentCompanyGUID": org_id,
                "CurrentCompanyName": name_path,
                "CheckBusiness": False,
                "ProcessModuleGUID": ProcessModuleGUID,
                "HandleFrom": "iPhone",
                "DontSelectProcessModule": "1",
                "DepartRoleList": [{
                    "DepartSeqGuid": org_id,
                    "DepartRoleGuid": org_id,
                    "DepartRoleName": name_path,
                    "Checked": 1,
                    "DepartRoleType": 1,
                    "StandardRoleProfessionalLineGuid": "00000000-0000-0000-0000-000000000000",
                    "StandardRoleGuid": "00000000-0000-0000-0000-000000000000"
                }
                ]
            }
        return {"user_guid":user_guid,"body":body}

    def AutoInitiateProcess_By_Module(self,user,ProcessModuleName='',BusinessGUID='',body='',OtherParams:dict=None):
        """
        静默发起接口，可以通过传user，模板名称，业务GUID发起此接口，或者通过直接传body发起接口
        :param user: 用户code
        :param ProcessName: 模板名称
        :param BusinessGUID: 业务GUID
        :param body: 请求体，当使用模板名称和业务GUID进行发起时，不需要body参数。反之，则需要完整body参数。
        :param OtherParams: body根节点下其他参数，使用字段传入其他参数，body会update进去此参数
        :return:
        """
        # 构建自动发起相关参数
        request_param = self._build_AutoInitiate_body(user,ProcessModuleName,BusinessGUID,body)
        user_guid = request_param['user_guid']
        body = request_param['body']
        # 更新其他参数
        if OtherParams is None:
            OtherParams = {}
        body.update(OtherParams)
        url = '/wf/Api/AutoInitiateProcess/AutoInitiateProcess'
        # 如果没传AuthenticationHeader，调用get_wf_token进行获取
        AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def ProcessInitiateAdapter_By_Module(self,user,ProcessModuleName='',BusinessGUID='',body='',OtherParams:dict=None):
        """
        发起适配接口，可以通过传user，模板名称，业务GUID发起此接口，或者通过直接传body发起接口
        :param user: 用户code
        :param ProcessName: 模板名称
        :param BusinessGUID: 业务GUID
        :param body: 请求体，当使用模板名称和业务GUID进行发起时，不需要body参数。反之，则需要完整body参数。
        :param OtherParams: body根节点下其他参数，使用字段传入其他参数，body会update进去此参数
        :return:
        """
        # 构建自动发起相关参数
        request_param = self._build_AutoInitiate_body(user, ProcessModuleName, BusinessGUID, body)
        user_guid = request_param['user_guid']
        body = request_param['body']
        # 更新其他参数
        if OtherParams is None:
            OtherParams = {}
        body.update(OtherParams)
        url = '/wf/Api/AutoInitiateProcess/ProcessInitiateAdapter'
        # 如果没传AuthenticationHeader，调用get_wf_token进行获取
        AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        print(f'【待校验响应体】:\n{resp.text}')
        return resp

    def MobileProcessInitiate_By_Module(self, user,ProcessModuleName='',BusinessGUID='',ApproveStepDTOList='',StepAuditors:dict=None,OtherParams:dict=None, body=''):
        """
        静默发起选人接口，如果接口需要正常发起，ApproveStepDTOList必传，当使用模板名称和业务GUID进行发起时，不需要body参数。反之，则需要完整body参数。
        :param user: 用户code
        :param ProcessName: 模板名称
        :param BusinessGUID: 业务GUID
        :param ApproveStepDTOList: 静默发起适配接口的响应参数
        :param OtherParams: body根节点下其他参数，使用字段传入其他参数，body会update进去此参数
        :param body: 请求体，当使用模板名称和业务GUID进行发起时，不需要body参数。反之，则需要完整body参数。
        :return:
        """
        # 构建自动发起相关参数
        request_param = self._build_AutoInitiate_body(user, ProcessModuleName, BusinessGUID, body)
        user_guid = request_param['user_guid']
        body = request_param['body']
        # 更新其他参数
        if OtherParams is None:
            OtherParams = {}
        body.update(OtherParams)
        if StepAuditors is None:
            StepAuditors = {}
        # StepAuditors = {"开始":["系统管理员"],"系统管理员审批":["系统管理员"],"结束":["系统管理员"]}
        # 根据步骤和责任人，更新选中标识，否则无法发起
        for StepName,auditors in StepAuditors.items():
            # 获取步骤责任人姓名
            for username in auditors:
                jsonpath_expr = jsonpath.jsonpath(ApproveStepDTOList,
                                  f'$.[?(@.StepName== "{StepName}")].Nodes[?(@.AuditorName== "{username}")]')
                # 判断表达式存在，再进行选中标识更新
                if jsonpath_expr:
                    jsonpath_expr[0].update({"Checked": 1})
                else:
                    assert False,Logger.error(f'步骤名【{StepName}】或对应步骤责任人【{username}】不存在,请检查yml数据源！')
        # 将json转义成字符串,ensure_ascii=False，防止中文被转义
        ApproveStepDTOList = simplejson.dumps(ApproveStepDTOList,ensure_ascii=False)
        # 更新静默发起适配接口的响应参数
        body.update({"ApproveStepDTOList":ApproveStepDTOList})
        url = '/wf/Api/AutoInitiateProcess/MobileProcessInitiate'
        # 如果没传AuthenticationHeader，调用get_wf_token进行获取
        AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp


    def MobileProcessReInitiate_By_Module(self, user,ProcessModuleName='',BusinessGUID='',OtherParams:dict=None, body=''):
        """
        静默发起重新发起流程接口
        :param user: 用户code
        :param ProcessName: 模板名称
        :param BusinessGUID: 业务GUID
        :param OtherParams: body根节点下其他参数，使用字段传入其他参数，body会update进去此参数
        :param body: 请求体，当使用模板名称和业务GUID进行发起时，不需要body参数。反之，则需要完整body参数。
        :return:
        """
        # 构建自动发起相关参数
        request_param = self._build_AutoInitiate_body(user, ProcessModuleName, BusinessGUID, body)
        user_guid = request_param['user_guid']
        body = request_param['body']
        # 更新其他参数
        if OtherParams is None:
            OtherParams = {}
        body.update(OtherParams)
        url = '/wf/Api/AutoInitiateProcess/MobileProcessReInitiate'
        # 如果没传AuthenticationHeader，调用get_wf_token进行获取
        AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def GetSelectProcessModuleRecord(self,body,user_guid='',AuthenticationHeader=''):
        """
        通过业务类型获取流程模板接口，body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/processmodule/GetSelectProcessModuleRecord'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def GetProcessModuleActionList(self,body,user_guid='',AuthenticationHeader=''):
        """
        获取流程模板状态，body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/processmodule/GetProcessModuleActionList'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def GetBusinessTypeList(self,body,user_guid='',AuthenticationHeader=''):
        """
        获取业务类型接口，body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/businesstype/GetBusinessTypeList'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='get', body=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def SaveDraft(self,body,user_guid='',AuthenticationHeader=''):
        """
        保存草稿，body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/ProcessEntiy/SaveDraft'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp

    def DeleteDraft(self,body,user_guid='',AuthenticationHeader=''):
        """
        删除草稿，body必传；user_guid和AuthenticationHeader传一个即可。
        :param body: 必传
        :param user_guid: 如果AuthenticationHeader没传，user_guid必传
        :param AuthenticationHeader: 如果user_guid没传，AuthenticationHeader必传
        :return:
        """
        url = '/wf/api/ProcessEntiy/DeleteDraft'
        if AuthenticationHeader=='':
            # 如果没传AuthenticationHeader，调用get_wf_token进行获取
            AuthenticationHeader = self.get_wf_token(user_guid=user_guid).json()['data']
        resp = self.send(url, method='post', payload=body,
                         headers={"AuthenticationHeader": AuthenticationHeader, "Content-Type": "application/json"})
        return resp
